package ar.edu.utn.frba.dds.aterrizar;

import java.util.ArrayList;

import org.junit.Before;
import org.junit.Test;

import ar.edu.utn.frba.dds.aterrizar.busquedas.*;
import ar.edu.utn.frba.dds.aterrizar.mocks.MockAerolineaLanchitaOriginal;
import ar.edu.utn.frba.dds.aterrizar.usuarios.*;
import ar.edu.utn.frba.dds.aterrizar.aerolineas.*;
import ar.edu.utn.frba.dds.aterrizar.criterioDeOrden.*;

import static org.junit.Assert.*;

public class AerolineaLanchitaTest {
	Usuario usuarioEstandarsinRestriccion;
	Busqueda sinRestriccion;
	Busqueda restriccionDeClaseYUbicacion;
	Busqueda busquedaVacia;
	Usuario usuarioVIPSinRestricciones;
	Usuario usuarioNoPagasinRestriccion;
	Usuario usuarioVIPConRestriccionesDeClaseYUbicacion;
	CondicionesExtraBuilder condicionesExtraBuilderUbicacionYClaseBuilder;
	CondicionesExtraBuilder condicionesExtraBuilderEmptyBuilder;
	CondicionesExtra condicionesExtraPrimeraClaseYUbicacionCentro;
	CondicionesExtra condicionesExtraEmpty;
	CondicionesExtra incluirReservados;
	CriterioDeOrden criterioDeOrden;
	OperadorDeAerolineas operador;

	@Before
	public void setUp() {
	OperadorDeAerolineas.createInstance();
	operador = OperadorDeAerolineas.getInstance();
	operador.agregarAerolinea(new AerolineaLanchitaAdapter(new MockAerolineaLanchitaOriginal()));
	condicionesExtraBuilderUbicacionYClaseBuilder = new CondicionesExtraBuilder();
	condicionesExtraBuilderEmptyBuilder = new CondicionesExtraBuilder();
	condicionesExtraPrimeraClaseYUbicacionCentro = condicionesExtraBuilderUbicacionYClaseBuilder.addClase("P").addClase("T").addUbicacion("V").addRangoPrecio(150,10000).build();
	condicionesExtraEmpty = condicionesExtraBuilderEmptyBuilder.build();
	sinRestriccion = new Busqueda("EZE", "USA", new RangoFechas("20/12/2012", null, null, null), condicionesExtraEmpty);
	restriccionDeClaseYUbicacion = new Busqueda("EZE", "USA", new RangoFechas("20/12/2012", null, null, null), condicionesExtraPrimeraClaseYUbicacionCentro);
	busquedaVacia = new Busqueda(null, null, new RangoFechas(null, null, null, null), null);
	usuarioEstandarsinRestriccion = new Usuario("Pepo", new Estandar(),"Pepon","1.232.321");
	usuarioVIPSinRestricciones = new Usuario("Pipo",new VIP(),"Pipon","36.200.287");
	usuarioNoPagasinRestriccion = new Usuario("Pepe",new NoPaga(),"Pompin","20.456.058");
	usuarioVIPConRestriccionesDeClaseYUbicacion = new Usuario("Pepa", new VIP(), "Pipa", "0");
	}
	
	@Test
	public void calculoDePrecioDeUnVueloParaUsuarioEstandar()  {
		Vuelo vuelo = operador.encontrarVueloPorCodigo("01202022220202","3"); 
		assertEquals(183.885, vuelo.getPrecioPara(usuarioEstandarsinRestriccion), 0.001);
	}
	
	@Test
	public void calculoDePrecioDeUnVueloParaUsuarioVIP() {
		Vuelo vuelo = operador.encontrarVueloPorCodigo("01202022220202","3"); 
		assertEquals(183.885, vuelo.getPrecioPara(usuarioVIPSinRestricciones), 0.001);
	}
	
	@Test
	public void calculoDePrecioDeUnVueloParaUsuarioNoPaga() {
		Vuelo vuelo = operador.encontrarVueloPorCodigo("01202022220202","3"); 
		assertEquals(203.885, vuelo.getPrecioPara(usuarioNoPagasinRestriccion), 0.001);
	}
	
	@Test (expected = VueloNoVisibleException.class)
	public void compraDeVueloNovisible() {
		Vuelo vueloPreCompra = operador.encontrarVueloPorCodigo("01202022220202","3");
		assertEquals("D", vueloPreCompra.getEstado());
		usuarioEstandarsinRestriccion.comprarVuelo(vueloPreCompra);
		Vuelo vueloPostCompra = operador.encontrarVueloPorCodigo("01202022220202","3"); 
		assertEquals("C", vueloPostCompra.getEstado());
	}
	
	@Test (expected = VueloNoVisibleException.class)
	public void noSePuedenComprarVueosNoVisibles() {
		Vuelo vueloPreCompra = operador.encontrarVueloPorCodigo("01202022220202","3"); 
		assertEquals("D", vueloPreCompra.getEstado());
		usuarioEstandarsinRestriccion.comprarVuelo(vueloPreCompra);
	}
	
	@Test
	public void cantidadVuelosParaUnUsuarioVIPsinRestriccionesExtra() {
		ArrayList<Vuelo> vuelos = usuarioVIPSinRestricciones.buscarVuelos(busquedaVacia);
		assertEquals(10, vuelos.size());
	}
	
	@Test
	public void cantidadVuelosParaUnUsuarioEstandarsinRestriccionesExtra() {
		ArrayList<Vuelo> vuelos = usuarioEstandarsinRestriccion.buscarVuelos(busquedaVacia);
		assertEquals(3, vuelos.size());
	}
	
	@Test
	public void cantidadVuelosParaUnUsuarioNoPagaSinRestriccionesExtra() {
		ArrayList<Vuelo> vuelos = usuarioNoPagasinRestriccion.buscarVuelos(busquedaVacia);
		assertEquals(3, vuelos.size());
	}
	
	@Test
	public void cantidadVuelosParaVIPConRestriccionesDePrimeraClaseYUbicacionCentro() {
		ArrayList<Vuelo> vuelos = usuarioVIPConRestriccionesDeClaseYUbicacion.buscarVuelos(restriccionDeClaseYUbicacion);
		assertEquals(1, vuelos.size());
	}
	
	@Test
	public void cantidadDeVuelosSinIncluirReservados() {
		ArrayList<Vuelo> vuelos = usuarioVIPConRestriccionesDeClaseYUbicacion.buscarVuelos(restriccionDeClaseYUbicacion);
		assertEquals(1, vuelos.size());
	}
	
	@Test
	public void cantidadDeVuelosIncluyendoReservados() {
		restriccionDeClaseYUbicacion.setIncluirReservados();
		ArrayList<Vuelo> vuelos = usuarioVIPConRestriccionesDeClaseYUbicacion.buscarVuelos(restriccionDeClaseYUbicacion);
		assertEquals(1, vuelos.size());
	}
	
	@Test
	public void cantidadDeVuelosDisponiblesDespuesDeReservar() {
		ArrayList<Vuelo> vuelosPreCompra = usuarioEstandarsinRestriccion.buscarVuelos(busquedaVacia);
		assertEquals(3, vuelosPreCompra.size());
		Vuelo vuelo = operador.encontrarVueloPorCodigo("01202022220008","3");
		usuarioEstandarsinRestriccion.reservarVuelo(vuelo);
		Vuelo vueloPostCompra = operador.encontrarVueloPorCodigo("01202022220008","3");
		assertEquals("R", vueloPostCompra.getEstado());
		ArrayList<Vuelo> vuelosPosCompra = usuarioEstandarsinRestriccion.buscarVuelos(busquedaVacia);
		assertEquals(2, vuelosPosCompra.size());
	}
	
	@Test (expected = VueloNoVisibleException.class)
	public void reservarVueloNoVisible() {
		Vuelo vueloPreCompra = operador.encontrarVueloPorCodigo("01202012315523","8"); 
		assertEquals("D", vueloPreCompra.getEstado());
		usuarioEstandarsinRestriccion.reservarVuelo(vueloPreCompra);
		Vuelo vueloPostCompra = operador.encontrarVueloPorCodigo("01202012315523","8"); 
		assertEquals("R", vueloPostCompra.getEstado());
	}
	
	@Test
	public void cantidadDeVuelosDisponiblesYReservadosDespuesDeComprar() {
		sinRestriccion.setIncluirReservados();
		ArrayList<Vuelo> vuelosPreCompra = usuarioEstandarsinRestriccion.buscarVuelos(busquedaVacia);
		assertEquals(3, vuelosPreCompra.size());
		Vuelo vuelo = operador.encontrarVueloPorCodigo("01202022220008","3");
		usuarioEstandarsinRestriccion.reservarVuelo(vuelo);
		Vuelo vueloPostCompra = operador.encontrarVueloPorCodigo("01202022220008","3");
		assertEquals("R", vueloPostCompra.getEstado());
		ArrayList<Vuelo> vuelosPosCompra = usuarioEstandarsinRestriccion.buscarVuelos(busquedaVacia);
		assertEquals(2, vuelosPosCompra.size());
	}
	
	@Test
	public void ordenAscendenteDePrecios() {
		ArrayList<Vuelo> vuelos = usuarioEstandarsinRestriccion.buscarVuelos(busquedaVacia);
		assertEquals(3, vuelos.size());		
		operador.ordenar(vuelos, new OrdenPrecioAscendiente());
		assertEquals(324.51, vuelos.get(0).getPrecioPara(usuarioEstandarsinRestriccion), 0.1);
		assertEquals(440.70, vuelos.get(1).getPrecioPara(usuarioEstandarsinRestriccion), 0.1);
		assertEquals(495.97, vuelos.get(2).getPrecioPara(usuarioEstandarsinRestriccion), 0.1);
	}
	
	@Test
	public void ordenDescendenteDePrecios() {
		ArrayList<Vuelo> vuelos = usuarioEstandarsinRestriccion.buscarVuelos(busquedaVacia);
		assertEquals(3, vuelos.size());		
		operador.ordenar(vuelos, new OrdenPrecioDescendiente());
		assertEquals(495.97, vuelos.get(0).getPrecioPara(usuarioEstandarsinRestriccion), 0.1);
		assertEquals(440.70, vuelos.get(1).getPrecioPara(usuarioEstandarsinRestriccion), 0.1);
		assertEquals(324.51, vuelos.get(2).getPrecioPara(usuarioEstandarsinRestriccion), 0.1);
	}
	
	@Test
	public void duracionDeVueloEnMinutos() {
		Vuelo vuelo = operador.encontrarVueloPorCodigo("01202022256565","2");
		int duracion = vuelo.getDuracionEnMinutos();
		assertEquals(25*60, duracion);
	}
	
	@Test
	public void duracionDeVueloEnString() {
		Vuelo vuelo = operador.encontrarVueloPorCodigo("01202022256565","2");
		String duracion = vuelo.getDuracionEnStringHora();
		assertEquals("25:00", duracion);
	}
	
	@Test
	public void ordenAscendenteDeDuracionDeVuelos() {
		ArrayList<Vuelo> vuelos = usuarioVIPSinRestricciones.buscarVuelos(busquedaVacia);
		assertEquals(10, vuelos.size());
		operador.ordenar(vuelos, new OrdenPorDuracion());
		assertEquals(520, vuelos.get(0).getDuracionEnMinutos());
		assertEquals("8:40", vuelos.get(0).getDuracionEnStringHora());
		assertEquals(520, vuelos.get(1).getDuracionEnMinutos());
		assertEquals("8:40", vuelos.get(1).getDuracionEnStringHora());
		assertEquals(520, vuelos.get(2).getDuracionEnMinutos());
		assertEquals("8:40", vuelos.get(2).getDuracionEnStringHora());
		assertEquals(720, vuelos.get(3).getDuracionEnMinutos());
		assertEquals("12:00", vuelos.get(3).getDuracionEnStringHora());
		assertEquals(720, vuelos.get(4).getDuracionEnMinutos());
		assertEquals("12:00", vuelos.get(4).getDuracionEnStringHora());
		assertEquals(720, vuelos.get(5).getDuracionEnMinutos());
		assertEquals("12:00", vuelos.get(5).getDuracionEnStringHora());
		assertEquals(745, vuelos.get(6).getDuracionEnMinutos());
		assertEquals("12:25", vuelos.get(6).getDuracionEnStringHora());
		assertEquals(745, vuelos.get(7).getDuracionEnMinutos());
		assertEquals("12:25", vuelos.get(7).getDuracionEnStringHora());
		assertEquals(745, vuelos.get(8).getDuracionEnMinutos());
		assertEquals("12:25", vuelos.get(8).getDuracionEnStringHora());
		assertEquals(1500, vuelos.get(9).getDuracionEnMinutos());
		assertEquals("25:00", vuelos.get(9).getDuracionEnStringHora());
	}
	
	@Test
	public void ordenAscendentePorPopularidadDeVuelos() {
		Vuelo vuelo = operador.encontrarVueloPorCodigo("01202022256565", "2");
		usuarioVIPSinRestricciones.comprarVuelo(vuelo);
		assertEquals(1, vuelo.getAerolinea().getCantidadDeAsientosVendidos("01202022256565"));
		ArrayList<Vuelo> vuelos = usuarioVIPSinRestricciones.buscarVuelos(busquedaVacia);
		assertEquals(9, vuelos.size());
		operador.ordenar(vuelos, new OrdenPopularidad());
		assertEquals(1, vuelos.get(0).getAerolinea().getCantidadDeAsientosVendidos(vuelos.get(0).getCodigoDeVuelo()));
		assertEquals(1, vuelos.get(1).getAerolinea().getCantidadDeAsientosVendidos(vuelos.get(1).getCodigoDeVuelo()));
		assertEquals(0, vuelos.get(2).getAerolinea().getCantidadDeAsientosVendidos(vuelos.get(2).getCodigoDeVuelo()));
		assertEquals(0, vuelos.get(3).getAerolinea().getCantidadDeAsientosVendidos(vuelos.get(3).getCodigoDeVuelo()));
		assertEquals(0, vuelos.get(4).getAerolinea().getCantidadDeAsientosVendidos(vuelos.get(4).getCodigoDeVuelo()));
		assertEquals(0, vuelos.get(5).getAerolinea().getCantidadDeAsientosVendidos(vuelos.get(5).getCodigoDeVuelo()));
		assertEquals(0, vuelos.get(6).getAerolinea().getCantidadDeAsientosVendidos(vuelos.get(6).getCodigoDeVuelo()));
		assertEquals(0, vuelos.get(7).getAerolinea().getCantidadDeAsientosVendidos(vuelos.get(7).getCodigoDeVuelo()));
		assertEquals(0, vuelos.get(8).getAerolinea().getCantidadDeAsientosVendidos(vuelos.get(8).getCodigoDeVuelo()));
	}
	
}